package com.iot08.api.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.iot08.api.config.redis.RedisFilterService;
import com.iot08.api.constant.Constant;
import com.iot08.api.response.DeviceAttentionResp;
import com.iot08.api.response.DeviceMessageResp;
import com.iot08.api.utils.buckettool.BaseBucketTool;
import com.iot08.api.utils.request.ParamHandle;
import com.iot08.api.vo.request.GetMessageReqVO;
import com.iot08.api.vo.request.MessageIdsParamReqVO;
import com.iot08.api.vo.request.UnReadMessagesReqVO;
import com.iot08.api.vo.request.base.BaseAccountReqVO;
import com.iot08.common.constant.CacheEnum;
import com.iot08.common.entity.app.*;
import com.iot08.common.service.base.BaseService;
import com.iot08.common.utils.CollectionUtil;
import com.iot08.common.utils.DateUtil;
import com.iot08.common.utils.StringUtil;
import com.iot08.common.utils.response.ResponseEnum;
import com.iot08.common.utils.response.ResponseMap;
import com.mongodb.client.FindIterable;
import com.mongodb.client.model.Filters;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.*;

/**
 * @version 1.0
 * @Description:
 * @author: Rock
 * @time: 2020/11/20 14:28
 */
@Slf4j
@Service
public class DeviceMessageService extends BaseService<DeviceMessage> {

    @Resource
    private MongoTemplate mongoTemplate;
    @Resource
    private AccountService accountService;
    @Resource
    private ChatGroupService chatGroupService;
    @Resource
    private SingleChatGroupService singleChatGroupService;
    @Resource
    private RedisFilterService redisFilterService;
    @Resource
    private DeviceNotificationService deviceNotificationService;

    @Resource
    private DeviceAttentionService deviceAttentionService;
    @Resource
    private OpenidConfigService openidConfigService;

    @Resource
    private DevHCYAuthService devHCYAuthService;

    @Resource
    private BaseBucketTool baseBucketTool;

    @Resource
    private VipMemberService vipMemberService;


    /**
     * 获取消息中心数据
     *
     * @param vo
     * @time: 2020/11/14 14:21
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap list(GetMessageReqVO vo) {
        Account account = accountService.findById(vo.getOpenid());
        if (account == null) {
            log.info("Account is null. params={}", vo.toString());
            return ResponseMap.fail(ResponseEnum.STATUS2000.getCode(), ResponseEnum.STATUS2000.getMsg());
        }
        List<Document> documents = new ArrayList<>();
        Document query = new Document();
        //参数query处理
        ParamHandle.queryParamHandle(query, vo.getQuery());
        Double deletemsgtime = account.getDeletemsgtime();
        if(deletemsgtime != null){
            // 增加上 查询条件, 查询 t字段 > deletemsgtime 字后的数据
            query.put("t", new Document().append("$gt", deletemsgtime));
        }
        String nowTimeStr = String.valueOf(System.currentTimeMillis() / 1000);
        if (StringUtil.isBlank(vo.getImei())) {
            //全部 设备
            List<String> imeiList = new ArrayList<>();
            if (CollectionUtil.isNotEmpty(account.getChatGroupMap())) {
                List<ChatGroup> chatGroups = chatGroupService.listByIds(CollectionUtil.stringToObjectId(account.getChatGroupMap().keySet()));
                for (ChatGroup cg : chatGroups) {
                    if (cg != null && CollectionUtil.isNotEmpty(cg.getDeviceMap())) {
                        for (String key : cg.getDeviceMap().keySet()) {
                            imeiList.add(key);
                            //记录已读
                            String redisKey = String.format("%s", vo.getOpenid());
                            redisFilterService.hset(redisKey + CacheEnum.READ_IMEI_MSG_TIME.getKey(), key, nowTimeStr);
                        }
                    }
                }
            }
            if (imeiList.size() > 0) {
                query.put("i", new Document().append("$in", imeiList));
                messageQueryHandle(query, documents, vo.getNum());
            }
        } else {
            //单个设备
            //记录已读
            String key = String.format("%s", vo.getOpenid());
            redisFilterService.hset(key + CacheEnum.READ_IMEI_MSG_TIME.getKey(), vo.getImei(), nowTimeStr);
            query.put("i", vo.getImei());
            messageQueryHandle(query, documents, vo.getNum());
        }
        ResponseMap res = ResponseMap.success();
        res.put("messages", documents);
        return res;
    }


    /**
     * @description 查询最新的提醒/告警通知信息
     * @author cwj
     * @param [vo]
     * @return com.iot08.common.utils.response.ResponseMap
     * @date @time 2025/4/8 14:09
     **/
    public ResponseMap queryLatestMsgInfo(BaseAccountReqVO vo) {
        Account account = accountService.findById(vo.getOpenid());
        if (account == null) {
            log.info("Account is null. params={}", vo);
            return ResponseMap.fail(ResponseEnum.STATUS2000.getCode(), ResponseEnum.STATUS2000.getMsg());
        }
        ResponseMap res = ResponseMap.success();
        List<DeviceMessage> deviceMessages = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(account.getDeviceMap())) {
            String key = String.format("%s%s", vo.getOpenid(), CacheEnum.READ_IMEI_MSG_TIME.getKey());
            for (Map.Entry<String, Map<String, Object>> entry : account.getDeviceMap().entrySet()) {
                String lastReadTimeStr = redisFilterService.hget(key, entry.getKey());
                double lastReadTime = System.currentTimeMillis() / 1000d;
                if (StringUtil.isNumeric(lastReadTimeStr)) {
                    lastReadTime = Double.parseDouble(lastReadTimeStr);
                } else if (StringUtil.isNumeric(entry.getValue().get("t"))) {
                    lastReadTime = Double.parseDouble(entry.getValue().get("t").toString());
                }
                Query query = new Query(Criteria.where("i").is(entry.getKey()).and("t").gt(lastReadTime));
                query.with(Sort.by(Sort.Order.desc("t"))).limit(1);
                DeviceMessage deviceMessage =  this.findOne(query);
                if(!ObjectUtils.isEmpty(deviceMessage)) {
                    deviceMessages.add(deviceMessage);
                }
            }
        }
        if(!CollectionUtils.isEmpty(deviceMessages)) {
           deviceMessages.sort(Comparator.comparingDouble(m -> Double.parseDouble(m.getTime().toString())));
           DeviceMessage deviceMessage = deviceMessages.get(deviceMessages.size()-1);
           DeviceMessageResp deviceMessageResp = new DeviceMessageResp();
           deviceMessageResp.settingDeviceMessageRespObject(deviceMessage);
           res.put("deviceMessageResp",deviceMessageResp);
        }
        DeviceAttention deviceAttention = deviceAttentionService.queryLatestAttentionInfo(account);
        if(!ObjectUtils.isEmpty(deviceAttention)){
            DeviceAttentionResp deviceAttentionResp = new DeviceAttentionResp();
            deviceAttentionResp.settingDeviceAttentionRespObject(deviceAttention);
            res.put("deviceAttentionResp",deviceAttentionResp);
        }
        return res;
    }




    /**
     * 消息查询处理
     *
     * @param query
     * @param documents
     * @time: 2020/11/19 16:31
     * @author: Rock
     * @version 1.0
     */
    private void messageQueryHandle(Document query, List<Document> documents, int num) {
        FindIterable<Document> document = this.findDoc(query, Filters.eq("_id", -1), 0, num);
        for (Document d : document) {
            d.put("id", d.get("_id").toString());
            d.put("imei", d.getString("i"));
            d.put("timestamp", d.get("t"));
            d.put("type", d.get("T"));
            if ("photograph".equals(d.get("T"))) {
                d.put("photographID", d.get("photoID") == null ? null : d.get("photoID").toString());
                d.put("url", baseBucketTool.getDOMAIN() + BaseBucketTool.PHOTOGRAPH_COMMON_PATH + d.getString("image"));
                d.put("thumbURL", baseBucketTool.getDOMAIN() + BaseBucketTool.PHOTOGRAPH_COMMON_PATH + d.getString("thumb"));
                d.remove("photoID");
                d.remove("image");
                d.remove("thumb");
            }
            d.remove("T");
            d.remove("t");
            d.remove("i");
            d.remove("_id");
            documents.add(d);
        }
    }

    /**
     * 删除消息中心数据
     *
     * @param vo
     * @time: 2020/11/20 14:27
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap dels(MessageIdsParamReqVO vo) {
        if (vo.getMessageIds() != null) {
            JSONArray idArr = JSON.parseArray(vo.getMessageIds());
            if(idArr.size() > 0){
                List<ObjectId> ids = new ArrayList<>();
                for (int i = 0; i < idArr.size(); i++) {
                    if (ObjectId.isValid(idArr.getString(i))) {
                        ids.add(new ObjectId(idArr.getString(i)));
                    }
                }
                this.delByIds(ids);
            }
        }else{
            accountService.updateById(vo.getOpenid(), new Update().set("deletemsgtime", DateUtil.nowTimestampToLong()));
            log.info("没有传messageId的情况下, 删除消息中心数据只是更新 用户 deletemsgtime字段 : "+DateUtil.nowTimestampToLong());
        }

        return ResponseMap.success();
    }

    /**
     * @param deviceMessage
     * @time: 2020/12/16 17:11
     * @author: Rock
     * @version 1.0
     */
    @Override
    public DeviceMessage save(DeviceMessage deviceMessage) {
        //所有记录的失效时间天数 3个月
        deviceMessage.setTime(DateUtil.nowTimestampToDouble());
        deviceMessage.setExpiryAt(DateUtil.getSystemExpiryAt());
        return mongoTemplate.save(deviceMessage);
    }

    /**
     * 获取当前用户是否有未读消息
     * {
     *     code: 0
     *     sysMsgIsUnread:     [int] //未读的系统消息
     *     userAttentionMsgIsUnread: [int] //关注信息未读消息
     *     allDevUnreadList:   [list] // 全部未读设备的消息
     *         [
     *             {
     *                 "imei": [str],
     *                 "imeiUnreadRemindMsg": [int],  //未读提醒消息(告警消息)
     *                 "imeiUnreadChatMsg": [int],    //未读聊天消息
     *                 "imeiUnreadSingleChatMsg": [int] //单聊的未读消息
     *             },
     *         ]
     * }
     * @param vo
     * @time: 2021/1/28 11:15
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap getUnReadMessages(UnReadMessagesReqVO vo) {
        Account account = accountService.findById(vo.getOpenid());
        Document document = accountService.findDocById(vo.getOpenid());
        if (account == null || document == null) {
            log.info("Account is null. params={}", vo.toString());
            return ResponseMap.fail(ResponseEnum.STATUS2000.getCode(), ResponseEnum.STATUS2000.getMsg());
        }
        ResponseMap res = ResponseMap.success();
        //检查用户是否是会员,是会员跟不是会员未读条数会有所不同
        VipMember vipMember = vipMemberService.queryVipMemberByOpenid(vo.getOpenid());
        if ("all".equals(vo.getType())) {
            List<Map<String, Object>> tempData = new ArrayList<>();
            if (CollectionUtil.isNotEmpty(account.getDeviceMap())) {
                String key = String.format("%s%s", vo.getOpenid(), CacheEnum.READ_IMEI_MSG_TIME.getKey());
                for (Map.Entry<String, Map<String, Object>> entry : account.getDeviceMap().entrySet()) {
                    Map<String, Object> tempMap = new HashMap<>();
                    tempMap.put("imei", entry.getKey());
                    //log.info("entry的最底层内容：{}",entry.getValue().get("g"));
                    if(ObjectUtils.isEmpty(vipMember)){
                        //非会员未读记录
                        if (StringUtil.isNotBlank(entry.getValue().get("g")) && StringUtil.isNotBlank(document.get(Constant.NO_VIP_UNREAD_TIME_PREFIX+entry.getValue().get("g")))) {
                            tempMap.put("imeiUnreadChatMsg", document.get(Constant.NO_VIP_UNREAD_TIME_PREFIX+entry.getValue().get("g")));
                        } else {
                            tempMap.put("imeiUnreadChatMsg", 0);
                        }
                    } else {
                        if (StringUtil.isNotBlank(entry.getValue().get("g")) && StringUtil.isNotBlank(document.get(entry.getValue().get("g")))) {
                            tempMap.put("imeiUnreadChatMsg", document.get(entry.getValue().get("g")));
                        } else {
                            tempMap.put("imeiUnreadChatMsg", 0);
                        }
                    }
                    String lastReadTimeStr = redisFilterService.hget(key, entry.getKey());
                    double lastReadTime = System.currentTimeMillis() / 1000d;
                    if (StringUtil.isNumeric(lastReadTimeStr)) {
                        lastReadTime = Double.parseDouble(lastReadTimeStr);
                    } else if (StringUtil.isNumeric(entry.getValue().get("t"))) {
                        lastReadTime = Double.parseDouble(entry.getValue().get("t").toString());
                    }
                    Query query = new Query(Criteria.where("i").is(entry.getKey()).and("t").gt(lastReadTime));
                    tempMap.put("imeiUnreadRemindMsg", this.count(query));

                    //单聊此用户未读消息 (因为只有一个,记录在单聊群组上)
                    SingleChatGroup tempSingleG = singleChatGroupService.findByImeiAndOpenid(entry.getKey(), vo.getOpenid());
                    if(ObjectUtils.isEmpty(vipMember)) {
                        if(tempSingleG == null){
                            tempMap.put("imeiUnreadSingleChatMsg" , 0);
                        }else {
                            tempMap.put("imeiUnreadSingleChatMsg" ,tempSingleG.getNoVipBage());
                        }
                    } else {
                        if(tempSingleG == null){
                            tempMap.put("imeiUnreadSingleChatMsg" , 0);
                        }else {
                            tempMap.put("imeiUnreadSingleChatMsg" ,tempSingleG.getBage());
                        }
                    }

                    //检查和彩云的小红点
                    DevHCYAuth devHCYAuth = devHCYAuthService.findById(entry.getKey());
                    if(devHCYAuth != null){
                        try{
                            String hcyPhotosUnreadListStr = devHCYAuth.getHcyPhotosUnreadListStr();
                            if(hcyPhotosUnreadListStr != null && hcyPhotosUnreadListStr.length() > 2){
                                JSONArray unreadList = JSONArray.parseArray(hcyPhotosUnreadListStr);
                                if(unreadList.contains(vo.getOpenid())){
                                    tempMap.put("imeiHcyPhotosUnread", 1);                                    //显示
                                }else{
                                    tempMap.put("imeiHcyPhotosUnread", 0);
                                }
                            }else{
                                tempMap.put("imeiHcyPhotosUnread", 0);
                            }
                        }catch (Exception e){
                            log.error("imei:"+entry.getKey()+" 解析和彩云移动云盘未读标识时报错 "+e.getMessage(), e);
                        }

                    }
                    tempData.add(tempMap);
                }
            }
            res.put("allDevUnreadList", tempData);
        }

        //关注消息 的未读数量
        long userAttentionMsgIsUnread = 0;
        //关注消息的最新未读时间
        Object lastReadUserAttentionTimeStr = redisFilterService.get(String.format("%s%s", vo.getOpenid(), CacheEnum.READ_USER_ATTENTION_MSG_TIME.getKey()));
        if (StringUtil.isBlank(lastReadUserAttentionTimeStr)) {
            lastReadUserAttentionTimeStr = account.getDeleteNotificationtime() == null ? "" : account.getDeleteNotificationtime();
        }
        if (StringUtil.isNotBlank(lastReadUserAttentionTimeStr)) {
            double lastReadUserAttentionTime = new Double(lastReadUserAttentionTimeStr.toString());
            if (account.getDeleteNotificationtime() != null && lastReadUserAttentionTime < account.getDeleteNotificationtime()) {
                lastReadUserAttentionTime = account.getDeleteNotificationtime();
            }
            Query query = new Query();
            query.addCriteria(Criteria.where("openid").is(vo.getOpenid()).and("t").gt(lastReadUserAttentionTime));
            userAttentionMsgIsUnread = deviceAttentionService.count(query);
        }
        res.put("userAttentionMsgIsUnread", userAttentionMsgIsUnread);

        long sysMsgIsUnread = 0;
        Object lastReadTimeStr = redisFilterService.get(String.format("%s%s", vo.getOpenid(), CacheEnum.READ_SYS_MSG_TIME.getKey()));
        if (StringUtil.isBlank(lastReadTimeStr)) {
            lastReadTimeStr = account.getDeleteNotificationtime() == null ? "" : account.getDeleteNotificationtime();
        }
        if (StringUtil.isNotBlank(lastReadTimeStr)) {
            List<String> showMsgIdList = new ArrayList<>();
            OpenidConfig openidConfig = openidConfigService.findById(vo.getOpenid());
            if (openidConfig != null && openidConfig.getShowMsgIdList() != null) {
                showMsgIdList.addAll(openidConfig.getShowMsgIdList());
            }
            Set<ObjectId> showMsgIdSet = CollectionUtil.stringToObjectId(showMsgIdList);
            double lastReadTime = new Double(lastReadTimeStr.toString());
            if (account.getDeleteNotificationtime() != null && lastReadTime < account.getDeleteNotificationtime()) {
                lastReadTime = account.getDeleteNotificationtime();
            }
            Criteria criteria = Criteria.where("status").is(1).and("t").gt(lastReadTime);
            criteria.orOperator(Criteria.where("openid").exists(false).and("accept_user").is("all"),
                    Criteria.where("openid").is("").and("accept_user").is("all"),
                    Criteria.where("openid").is(vo.getOpenid()),
                    Criteria.where("accept_user").is("group").and("_id").in(showMsgIdSet));
            sysMsgIsUnread = deviceNotificationService.count(new Query(criteria));
        }
        res.put("sysMsgIsUnread", sysMsgIsUnread);
        return res;
    }
}
